﻿
Imports Clicknator
Imports System.Drawing
Imports System.IO



Public Class ClikinBaconForm


#Region " Constants "
    Private Const TEXT_MOUSE_SURVEY_TEMPLATE As String = "Cursor location: {0},{1} ({2},{3})"
    Private Const TEXT_MOUSE_SURVEYBUTTON_STOPPED As String = "Survey"
    Private Const TEXT_MOUSE_SURVEYBUTTON_STARTED As String = "Stop"
    Private Const TEXT_STATUS_TEMPLATE As String = "Status: {0}"
    Private Const TEXT_STATUS_READY As String = "Ready"
    Private Const TEXT_STATUS_RUNNING As String = "Running..."
    Private Const TEXT_STATUS_DONE As String = "Done!"
    Private Const TEXT_STATUS_PARSE_ERR As String = "Parsing Error!"
    Private Const TEXT_DIALOG_LINE_ERR_TEMPLATE As String = "Error on line: {0}!"
    Private Const TEXT_STATUS_SIMULATION_RUNNING As String = "Simulation Running..."
    Private Const TEXT_STATUS_SIMULATION_DONE As String = "Simulation Done!"
    Private Const TEXT_SCRIPT_CHANGED As String = "Script has changed. Save changes?"
    Private Const TEXT_LINE_NUMBER_INDICATOR As String = "ln: {0}"
    Private Const TEXT_COLUMN_NUMBER_INDICATOR As String = "col: {0}"

    Private Const HELP_DIRECTORY_START As String = ".\Documentation\Documentation.html"
    Private Const COMMAND_LENGTH As Int32 = 5
    Private Const FORM_OFFSET_X As Int32 = 7
    Private Const FORM_OFFSET_Y As Int32 = 70
#End Region

#Region " Private Members "
    Private playbackMacroEngine As Clickinator
    Private simulationMacroEngine As Clickinator
    Private simulationForm As TargetForm
    Private scriptDirty As Boolean = False
    Private scriptRecorder As RecordingScript
    Private currentlyRecording As Boolean = False
    Private currentlyPlaying As Boolean = False
    Private currentlySimulating As Boolean = False
    Private currentlySurveying As Boolean = False
    Private validCommandsBuffer As List(Of String) = Nothing
    Private previouslyExecutingLine As Int32 = -1
#End Region

#Region " Events "
    Private Sub GOButton_Click(sender As Object, e As EventArgs) Handles GOButton.Click
        DoNavigation(URLTextBox.Text)
    End Sub

    Private Sub URLTextBox_KeyPress(sender As Object, e As KeyPressEventArgs) Handles URLTextBox.KeyPress
        If Convert.ToInt32(e.KeyChar) = Keys.Enter Then
            DoNavigation(URLTextBox.Text)
        End If
    End Sub

    Private Sub SurveyTimer_Tick(sender As Object, e As EventArgs) Handles SurveyTimer.Tick
        SurveyMouse()
    End Sub

    Private Sub SurveyButton_Click(sender As Object, e As EventArgs) Handles SurveyButton.Click
        ToggleMouseSurvey()
    End Sub

    Private Sub BaconButton_Click(sender As Object, e As EventArgs) Handles PlayButton.Click
        BaconClick()
    End Sub

    Private Sub SimulateButton_Click(sender As Object, e As EventArgs) Handles SimulateButton.Click
        SimiliBacon()
    End Sub

    Private Sub MacroTextBox_TextChanged(sender As Object, e As EventArgs) Handles MacroTextBox.TextChanged
        StatusLabel.Text = String.Format(TEXT_STATUS_TEMPLATE, TEXT_STATUS_READY)
        scriptDirty = True
    End Sub

    Private Sub MacroTextBox_SelectionChanged(sender As Object, e As EventArgs) Handles MacroTextBox.SelectionChanged
        ShowMacroLineNumber()
    End Sub

    Private Sub ClikinBaconForm_Load(sender As Object, e As EventArgs) Handles Me.Load
        ShowHelp()
        SetInitialDialogDirectories()
    End Sub

    Private Sub HelpButtonBar_Click(sender As Object, e As EventArgs) Handles HelpButtonBar.Click
        ShowHelp()
    End Sub

    Private Sub SaveButton_Click(sender As Object, e As EventArgs) Handles SaveButton.Click
        DialogSave()
    End Sub

    Private Sub OpenButton_Click(sender As Object, e As EventArgs) Handles OpenButton.Click
        If scriptDirty Then
            If PromptChange() Then
                DialogOpen()
            End If
        Else
            DialogOpen()
        End If
    End Sub

    Private Sub NewButton_Click(sender As Object, e As EventArgs) Handles NewButton.Click
        If scriptDirty Then
            If PromptChange() Then
                EmptyScriptBox()
            End If
        Else
            EmptyScriptBox()
        End If
    End Sub

    Private Sub RecordButton_Click(sender As Object, e As EventArgs) Handles RecordButton.Click
        RecordDialog()
    End Sub

    Private Sub RecordTimer_Tick(sender As Object, e As EventArgs) Handles RecordTimer.Tick
        RecordState()
    End Sub

    Private Sub StopButton_Click(sender As Object, e As EventArgs) Handles StopButton.Click
        StopAction()
    End Sub

    Private Sub MainBrowser_DocumentCompleted(sender As Object, e As WebBrowserDocumentCompletedEventArgs) Handles MainBrowser.DocumentCompleted
        ShowCurrentUrl()
    End Sub

#End Region

#Region " For Delegates "
    Private Function GetCursorLocation() As Point
        Return MousePosition
    End Function

    Private Function GetWindowLocation() As Point
        Return New Point((Me.Left + Me.MainBrowser.Left + FORM_OFFSET_X), (Me.Top + Me.MainBrowser.Top + FORM_OFFSET_Y))
    End Function

    Private Sub DoSimulateMouseClick(ByVal downButton As Boolean, ByVal buttonNumber As Integer)
        simulationForm.DoButton(downButton, buttonNumber)
        simulationForm.Refresh()
    End Sub

    Private Sub DoSimulateMouseMove(ByVal screenLocation As Point)
        simulationForm.SetTarget(screenLocation)
        simulationForm.Refresh()
    End Sub

    Private Sub ShowMessageBox(ByVal messageText As String)
        MessageBox.Show(messageText)
    End Sub

#End Region


#Region "Private Methods"

    Private Sub DoNavigation(ByVal targetURL As String)
        MainBrowser.Navigate(targetURL)
    End Sub

    Private Sub SurveyMouse()

        Dim mouseCoords As Point = MousePosition
        Dim leftButton As Boolean = False
        Dim rightButton As Boolean = False
        Dim middleButton As Boolean = False

        'left button
        leftButton = (ClikinAPI.WhatIsKeyState(ClikinAPI.VK_LBUTTON) = ClikinAPI.VK_STATE_DOWN)

        'Middle
        middleButton = (ClikinAPI.WhatIsKeyState(ClikinAPI.VK_MBUTTON) = ClikinAPI.VK_STATE_DOWN)

        'Right
        rightButton = (ClikinAPI.WhatIsKeyState(ClikinAPI.VK_RBUTTON) = ClikinAPI.VK_STATE_DOWN)

        'Display mouse state on screen
        DisplayMouseState(mouseCoords, leftButton, middleButton, rightButton)

    End Sub

    Private Sub ToggleMouseSurvey()
        SurveyTimer.Enabled = Not SurveyTimer.Enabled
        currentlySurveying = SurveyTimer.Enabled
        UpdateToolbar()

        If SurveyTimer.Enabled Then
            SurveyButton.Text = TEXT_MOUSE_SURVEYBUTTON_STARTED
        Else
            SurveyButton.Text = TEXT_MOUSE_SURVEYBUTTON_STOPPED
        End If
    End Sub

    Private Sub BaconClick()
        'clean-up code
        TrimRTFBlankLines()
        HighlightText()

        playbackMacroEngine = New Clickinator(AddressOf Me.GetWindowLocation, AddressOf Me.GetCursorLocation, AddressOf Me.DoNavigation, AddressOf Me.ShowMessageBox, AddressOf DoSimulateMouseClick, AddressOf DoSimulateMouseMove)

        currentlyPlaying = True
        UpdateToolbar()
        StatusLabel.Text = String.Format(TEXT_STATUS_TEMPLATE, TEXT_STATUS_RUNNING)
        Me.Refresh()

        'Parse commands
        If playbackMacroEngine.ProcessMacro(MacroTextBox.Text) Then
            'run commands
            Do
                HighlightExecutingLine(playbackMacroEngine.GetInstructionIndex)
                playbackMacroEngine.Execute()
            Loop While playbackMacroEngine.MoveNext And (Not playbackMacroEngine.UserCancelled)

            StatusLabel.Text = String.Format(TEXT_STATUS_TEMPLATE, TEXT_STATUS_DONE)
        Else
            'error
            DisplayParseError(playbackMacroEngine.LastErrorLine)
        End If

        'trash object
        playbackMacroEngine = Nothing
        currentlyPlaying = False
        previouslyExecutingLine = -1
        Me.HighlightText()
        UpdateToolbar()
    End Sub

    Private Sub SimiliBacon()
        simulationForm = New TargetForm
        simulationForm.Owner = Me
        simulationForm.TopMost = True

        'clean-up code
        TrimRTFBlankLines()
        HighlightText()

        simulationMacroEngine = New Clickinator(AddressOf Me.GetWindowLocation, AddressOf Me.GetCursorLocation, AddressOf Me.DoNavigation, AddressOf Me.ShowMessageBox, AddressOf DoSimulateMouseClick, AddressOf DoSimulateMouseMove)

        currentlySimulating = True
        UpdateToolbar()
        simulationMacroEngine.SimulationStart()
        StatusLabel.Text = String.Format(TEXT_STATUS_TEMPLATE, TEXT_STATUS_SIMULATION_RUNNING)
        Me.Refresh()

        'Parse commands
        If simulationMacroEngine.ProcessMacro(MacroTextBox.Text) Then
            'run commands
            Do
                HighlightExecutingLine(simulationMacroEngine.GetInstructionIndex)
                simulationMacroEngine.Execute()
            Loop While simulationMacroEngine.MoveNext And (Not simulationMacroEngine.UserCancelled)

            StatusLabel.Text = String.Format(TEXT_STATUS_TEMPLATE, TEXT_STATUS_SIMULATION_DONE)
        Else
            'error
            DisplayParseError(simulationMacroEngine.LastErrorLine)
        End If

        'whatever happened; stop simulating
        simulationMacroEngine.SimulationStop()
        simulationMacroEngine = Nothing
        currentlySimulating = False
        simulationForm.Visible = False
        simulationForm = Nothing
        previouslyExecutingLine = -1
        Me.HighlightText()
        UpdateToolbar()
    End Sub

    Private Sub ShowHelp()
        URLTextBox.Text = String.Concat("file://", IO.Path.GetFullPath(My.Settings.DocumentationStartPage))
        DoNavigation(URLTextBox.Text)
    End Sub

    Private Sub DisplayMouseState(ByVal absoluteMouseCoords As Point, ByVal leftDown As Boolean, ByVal middleDown As Boolean, ByVal rightDown As Boolean)


        'location
        MouseSurveyLabel.Text = String.Format(TEXT_MOUSE_SURVEY_TEMPLATE, (absoluteMouseCoords.X - (Me.Left + MainBrowser.Left + FORM_OFFSET_X)), (absoluteMouseCoords.Y - (Me.Top + MainBrowser.Top + FORM_OFFSET_Y)), absoluteMouseCoords.X, absoluteMouseCoords.Y)

        'left button
        If leftDown Then
            MouseLeftLabel.BackgroundImage = My.Resources.StatusBarResource.mouse_l
        Else
            MouseLeftLabel.BackgroundImage = Nothing
        End If

        'Middle
        If middleDown Then
            MouseMiddleLabel.BackgroundImage = My.Resources.StatusBarResource.mouse_m
        Else
            MouseMiddleLabel.BackgroundImage = Nothing
        End If

        'Right
        If rightDown Then
            MouseRightLabel.BackgroundImage = My.Resources.StatusBarResource.mouse_r
        Else
            MouseRightLabel.BackgroundImage = Nothing
        End If


    End Sub

    Private Function PromptChange() As Boolean
        Dim ret As Boolean = False

        Select Case MessageBox.Show(TEXT_SCRIPT_CHANGED, Me.Text, MessageBoxButtons.YesNoCancel, MessageBoxIcon.Question)
            Case vbYes
                If DialogSave() Then
                    'user cancelled dialog; abort command
                    ret = True
                End If
            Case vbNo
                'there is nothing in the box!!!!
                ret = True
            Case vbCancel
                'cancel; abort command
                ret = False
        End Select

        Return ret
    End Function

    Private Function DialogSave() As Boolean
        Dim ret As Boolean = False

        If scriptSaveFile.ShowDialog() = Windows.Forms.DialogResult.OK Then
            ret = True
            TrimRTFBlankLines()
            SaveScriptToDisk(scriptSaveFile.OpenFile())
            HighlightText()
        End If

        Return ret
    End Function

    Private Sub DialogOpen()
        If scriptOpenFile.ShowDialog = Windows.Forms.DialogResult.OK Then
            LoadScriptFromDisk(scriptOpenFile.OpenFile())
            TrimRTFBlankLines()
            HighlightText()
        End If
    End Sub

    Private Sub SaveScriptToDisk(ByRef s As Stream)
        Dim w As New StreamWriter(s)

        w.Write(Me.MacroTextBox.Text)
        w.Flush()
        w.Close()

        scriptDirty = False
    End Sub

    Private Sub LoadScriptFromDisk(ByRef s As Stream)
        Dim r As New StreamReader(s)

        MacroTextBox.Text = ""
        MacroTextBox.Text = r.ReadToEnd
        r.Close()

        scriptDirty = False
    End Sub

    Private Sub EmptyScriptBox()
        Me.MacroTextBox.Text = ""
        scriptDirty = False
    End Sub

    Private Sub RecordDialog()
        Dim d As New RecordSettingsDialog
        Dim go As Boolean = False

        'ask the user to save if there is something in the macro box
        If Me.scriptDirty Then
            If PromptChange() Then
                go = True
            End If
        Else
            go = True
        End If

        If go Then
            If d.ShowDialog = Windows.Forms.DialogResult.OK Then
                StartRecording(d.RecordingSettings)
            End If
        End If

        d = Nothing
    End Sub

    Private Sub StartRecording(ByVal rSettings As RecordSettings)
        Me.MacroTextBox.Text = ""
        scriptRecorder = New RecordingScript(rSettings, AddressOf Me.GetWindowLocation)
        currentlyRecording = True
        UpdateToolbar()
        RecordTimer.Interval = rSettings.CursorSampleRefreshRate
        RecordTimer.Start()
    End Sub

    Private Sub RecordState()
        Dim mouseCoords As Point = MousePosition
        Dim leftButton As Boolean = False
        Dim rightButton As Boolean = False
        Dim middleButton As Boolean = False

        'left button
        leftButton = (ClikinAPI.WhatIsKeyState(ClikinAPI.VK_LBUTTON) = ClikinAPI.VK_STATE_DOWN)

        'Middle
        middleButton = (ClikinAPI.WhatIsKeyState(ClikinAPI.VK_MBUTTON) = ClikinAPI.VK_STATE_DOWN)

        'Right
        rightButton = (ClikinAPI.WhatIsKeyState(ClikinAPI.VK_RBUTTON) = ClikinAPI.VK_STATE_DOWN)

        'record state
        scriptRecorder.RecordWaitPeriod()
        scriptRecorder.RecordCursor(MousePosition)
        scriptRecorder.RecordMouseClick(MousePosition, leftButton, middleButton, rightButton)

        'Display mouse state on screen
        DisplayMouseState(mouseCoords, leftButton, middleButton, rightButton)
    End Sub

    Private Sub StopAction()

        If currentlyPlaying Then
            StopPlaying()
        ElseIf currentlyRecording Then
            StopRecording()
        ElseIf currentlySimulating Then
            StopSimulating()
        ElseIf currentlySurveying Then
            ToggleMouseSurvey()
        End If

    End Sub

    Private Sub StopPlaying()

        'stop playback
        'starting event will take care of the cleanup
        playbackMacroEngine.Cancel()

    End Sub

    Private Sub StopRecording()
        'stop recording
        RecordTimer.Stop()
        scriptRecorder.DoneRecording()
        Me.MacroTextBox.Text = scriptRecorder.ToString
        scriptRecorder = Nothing
        currentlyRecording = False
        UpdateToolbar()
    End Sub

    Private Sub StopSimulating()

        'stop simulating
        'starting event will take care of the cleanup
        simulationMacroEngine.Cancel()

    End Sub

    Private Sub UpdateToolbar()
        Dim i As Int32 = 0

        'toggle toolstrip buttons appropriately
        If currentlyPlaying Or currentlyRecording Or currentlySimulating Or currentlySurveying Then
            For i = 0 To (ControlStrip.Items.Count - 1)
                If ControlStrip.Items(i).GetType = StopButton.GetType Then
                    ControlStrip.Items(i).Enabled = False
                End If
            Next
            StopButton.Enabled = True
        Else
            For i = 0 To (ControlStrip.Items.Count - 1)
                If ControlStrip.Items(i).GetType = StopButton.GetType Then
                    ControlStrip.Items(i).Enabled = True
                End If
            Next
            StopButton.Enabled = False
        End If
    End Sub

    Private Sub SetInitialDialogDirectories()
        Me.scriptOpenFile.InitialDirectory = IO.Path.GetFullPath(".")
        Me.scriptSaveFile.InitialDirectory = IO.Path.GetFullPath(".")
    End Sub

    Private Sub HighlightText()
        Dim i As Int32
        Dim originalCarretLocation As Int32

        'reset color
        originalCarretLocation = MacroTextBox.SelectionStart
        MacroTextBox.SelectAll()
        MacroTextBox.SelectionColor = Color.Black
        MacroTextBox.SelectionBackColor = MacroTextBox.BackColor
        MacroTextBox.Select(0, 0)

        For i = 0 To (MacroTextBox.Lines.Count - 1)
            Dim isCommandValid As Boolean = True

            If IsSpecificCommand(MacroTextBox.Lines(i), Clickinator.COMMAND_COMMENT) Then
                'line is comment
                PaintRTFLine(i, My.Settings.ColorComment)
            ElseIf IsSpecificCommand(MacroTextBox.Lines(i), Clickinator.COMMAND_MESS) Then
                'message; param is string
                PaintRTFCommand(i, My.Settings.ColorCommand)
                PaintRTFParameter(i, My.Settings.ColorParameter)
            ElseIf IsSpecificCommand(MacroTextBox.Lines(i), Clickinator.COMMAND_SETV) _
                OrElse IsSpecificCommand(MacroTextBox.Lines(i), Clickinator.COMMAND_INCV) _
                OrElse IsSpecificCommand(MacroTextBox.Lines(i), Clickinator.COMMAND_DECV) Then

                'param is variable and always the first param
                PaintRTFCommand(i, My.Settings.ColorCommand)
                PaintRTFParameter(i, My.Settings.ColorVariable, 1)
            ElseIf IsValidCommand(MacroTextBox.Lines(i).Substring(0, COMMAND_LENGTH)) Then
                'some other valid command
                PaintRTFCommand(i, My.Settings.ColorCommand)
            Else
                'not a valid command
                PaintRTFLine(i, My.Settings.ColorHighlightError, True)
                isCommandValid = False
            End If

            If isCommandValid Then
                'highlight math operations
                PaintRTFParameterDelemitedString(i, My.Settings.ColorMath, Clickinator.MathStartDelemiter, Clickinator.MathEndDelemiter)

                'highlight variables
                PaintRTFParameterDelemitedString(i, My.Settings.ColorVariable, Clickinator.VariableStartDelemiter, Clickinator.VariableEndDelemiter)
            End If

        Next

        'set cursor to original position
        MacroTextBox.Select(originalCarretLocation, 0)

    End Sub

    ''' <summary>
    ''' Paint a specific line of the rich text box
    ''' </summary>
    ''' <param name="lineNumber"></param>
    ''' <param name="lineColor"></param>
    ''' <remarks></remarks>
    Private Sub PaintRTFLine(ByVal lineNumber As Int32, ByVal lineColor As System.Drawing.Color, Optional ByVal highlightLine As Boolean = False)
        Dim lineStart = MacroTextBox.GetFirstCharIndexFromLine(lineNumber)
        Dim lineEnd = CalculateLineEnd(lineNumber)

        'paint line
        PaintRTFArea(lineStart, (lineEnd - lineStart), lineColor, highlightLine)
    End Sub

    ''' <summary>
    ''' Paint the command portion of a line of the rich text box
    ''' </summary>
    ''' <param name="lineNumber"></param>
    ''' <param name="lineColor"></param>
    ''' <remarks></remarks>
    Private Sub PaintRTFCommand(ByVal lineNumber As Int32, ByVal lineColor As System.Drawing.Color)
        Dim lineStart = MacroTextBox.GetFirstCharIndexFromLine(lineNumber)

        'paint command
        PaintRTFArea(lineStart, COMMAND_LENGTH, lineColor, False)

    End Sub

    ''' <summary>
    ''' Paint the parameter portion of a line of the rich text box. You may paint single parameters as well.
    ''' </summary>
    ''' <param name="lineNumber"></param>
    ''' <param name="lineColor"></param>
    ''' <param name="parameterNumber"></param>
    ''' <remarks></remarks>
    Private Sub PaintRTFParameter(ByVal lineNumber As Int32, ByVal lineColor As System.Drawing.Color, Optional ByVal parameterNumber As Int32 = 0, Optional ByVal highlightParameter As Boolean = False)
        Dim lineStart = MacroTextBox.GetFirstCharIndexFromLine(lineNumber)

        If parameterNumber = 0 Then
            'paint all parameter section
            Dim lineEnd = CalculateLineEnd(lineNumber)

            'paint all parameters
            PaintRTFArea((lineStart + COMMAND_LENGTH), (lineEnd - (lineStart - COMMAND_LENGTH)), lineColor, highlightParameter)
        ElseIf parameterNumber > 0 Then
            'paint a single paramter
            Dim parameterCount As Int32
            Dim parameterString As String
            Dim parameterList As String()
            Dim parameterStart As Int32
            Dim parameterLength As Int32

            parameterString = MacroTextBox.Lines(lineNumber).Substring((COMMAND_LENGTH), (MacroTextBox.Lines(lineNumber).Length - COMMAND_LENGTH))
            parameterList = parameterString.Split(Clickinator.ParameterSeparator)
            parameterCount = parameterList.Count

            'only highlight if within range
            If parameterNumber <= parameterCount Then
                Dim i As Int32

                'also add the length of the command to the start index of the parameter
                parameterStart = COMMAND_LENGTH

                'calculate start index (add all *previous* parameter lengths)
                For i = 0 To (parameterNumber - 2)
                    parameterStart += parameterList(i).Length
                    parameterStart += Clickinator.ParameterSeparator.Length
                Next

                'calculate the end index of the parameter (we do not want to highlight the seperator)
                parameterLength = parameterList(parameterNumber - 1).Length

                'paint parameter
                PaintRTFArea((lineStart + parameterStart), parameterLength, lineColor, highlightParameter)
            End If


        End If
    End Sub

    ''' <summary>
    ''' Highlights a string within all parameters delemited by StartDelemiter and EndDelemiter
    ''' </summary>
    ''' <param name="lineNumber"></param>
    ''' <param name="lineColor"></param>
    ''' <param name="startDelemiter"></param>
    ''' <param name="endDelemiter"></param>
    ''' <param name="highlightParameter"></param>
    ''' <remarks></remarks>
    Private Sub PaintRTFParameterDelemitedString(ByVal lineNumber As Int32, ByVal lineColor As System.Drawing.Color, ByVal startDelemiter As String, ByVal endDelemiter As String, Optional ByVal highlightParameter As Boolean = False)
        'extract parameter portion
        Dim parameterString As String = MacroTextBox.Lines(lineNumber).Substring((COMMAND_LENGTH), (MacroTextBox.Lines(lineNumber).Length - COMMAND_LENGTH))

        Dim lineStartIndex = MacroTextBox.GetFirstCharIndexFromLine(lineNumber)
        Dim parameterStartIndex As Int32 = 0
        Dim parameterEndIndex As Int32 = 0

        'anticipated (first) read
        parameterStartIndex = parameterString.IndexOf(startDelemiter, parameterStartIndex)
        parameterEndIndex = parameterString.IndexOf(endDelemiter, parameterStartIndex + 1)

        'loop while there is a valid start and end index
        Do While ((parameterStartIndex > 0) AndAlso (parameterEndIndex > 0))
            'highlight delemited string
            PaintRTFArea((lineStartIndex + COMMAND_LENGTH + parameterStartIndex), (parameterEndIndex - parameterStartIndex + 1), lineColor, highlightParameter)

            'set start position for next read
            parameterStartIndex = parameterEndIndex + 1

            'get the next occurence of the start delemiter
            parameterStartIndex = parameterString.IndexOf(startDelemiter, parameterStartIndex)
            parameterEndIndex = parameterString.IndexOf(endDelemiter, parameterStartIndex + 1)
        Loop

    End Sub

    Private Sub PaintRTFArea(ByVal startIndex As Int32, ByVal areaLength As Int32, ByVal areaColor As System.Drawing.Color, ByVal highlightArea As Boolean)
        'select the area to paint
        MacroTextBox.Select(startIndex, areaLength)

        'do the actual painitng
        If highlightArea Then
            'highlight
            MacroTextBox.SelectionBackColor = areaColor
        Else
            'paint
            MacroTextBox.SelectionColor = areaColor
        End If
    End Sub


    ''' <summary>
    ''' removes empty lines from script TextBox
    ''' </summary>
    ''' <remarks></remarks>
    Private Sub TrimRTFBlankLines()
        Dim i As Int32
        Dim richLines As List(Of String) = MacroTextBox.Lines.ToList

        For i = (richLines.Count - 1) To 0 Step -1
            If String.IsNullOrWhiteSpace(richLines(i)) Then
                richLines.RemoveAt(i)
            End If
        Next

        MacroTextBox.Lines = richLines.ToArray
    End Sub

    ''' <summary>
    ''' Checkif the supplied command text is valid
    ''' </summary>
    ''' <param name="commandText"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function IsValidCommand(ByVal commandText As String) As Boolean
        Dim output As Boolean = False

        If validCommandsBuffer Is Nothing Then
            validCommandsBuffer = Clickinator.ValidCommands
        End If

        If Len(commandText.Length > (COMMAND_LENGTH - 1)) Then
            'longer part of the command supplied
            If commandText.Substring(4, 1) = Clickinator.InstructionSeparator Then
                'contains separator at the proper location
                If validCommandsBuffer.Contains(commandText.Substring(0, (COMMAND_LENGTH - 1))) Then
                    'valid command found
                    output = True
                End If
            End If
        ElseIf commandText.Length = (COMMAND_LENGTH - 1) Then
            'just the command bit supplied (proper length)
            If validCommandsBuffer.Contains(commandText) Then
                'valid command found
                output = True
            End If
        End If


        Return output
    End Function

    ''' <summary>
    ''' Returns true if commandText is of type specificCommandName
    ''' </summary>
    ''' <param name="commandText"></param>
    ''' <param name="specificCommandName"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function IsSpecificCommand(ByVal commandText As String, ByVal specificCommandName As String) As Boolean
        Return commandText.StartsWith(String.Concat(specificCommandName, Clickinator.InstructionSeparator))
    End Function

    ''' <summary>
    ''' Calculated the ending index of the RTF box
    ''' </summary>
    ''' <param name="lineNumber"></param>
    ''' <returns></returns>
    ''' <remarks></remarks>
    Private Function CalculateLineEnd(ByVal lineNumber As Int32) As Int32
        Dim output As Int32

        If lineNumber >= (MacroTextBox.Lines.Count - 1) Then
            'last line
            output = MacroTextBox.TextLength
        Else
            'normal line
            output = MacroTextBox.GetFirstCharIndexFromLine(lineNumber + 1) - 1
        End If

        Return output
    End Function

    ''' <summary>
    ''' displays a parsing error  to the user
    ''' </summary>
    ''' <param name="lineNumber"></param>
    ''' <remarks></remarks>
    Private Sub DisplayParseError(ByVal lineNumber As Int32)
        Dim originalCarretLocation As Int32
        originalCarretLocation = MacroTextBox.SelectionStart

        PaintRTFLine(lineNumber, My.Settings.ColorHighlightError, True)
        StatusLabel.Text = String.Format(TEXT_STATUS_TEMPLATE, TEXT_STATUS_PARSE_ERR)
        MacroTextBox.Select(originalCarretLocation, 0)

        MessageBox.Show(String.Format(TEXT_DIALOG_LINE_ERR_TEMPLATE, lineNumber), Me.Text, MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
    End Sub

    Private Sub ShowMacroLineNumber()
        Dim currLine As Int32 = 0
        Dim currColumn As Int32 = 0

        currLine = MacroTextBox.GetLineFromCharIndex(MacroTextBox.SelectionStart)
        currColumn = MacroTextBox.SelectionStart - MacroTextBox.GetFirstCharIndexOfCurrentLine

        Me.LineNumberLabel.Text = String.Format(TEXT_LINE_NUMBER_INDICATOR, currLine)
        Me.ColumnNumberLabel.Text = String.Format(TEXT_COLUMN_NUMBER_INDICATOR, currColumn)
    End Sub

    Private Sub ShowCurrentUrl()
        Me.URLTextBox.Text = MainBrowser.Document.Url.ToString
    End Sub

    Private Sub HighlightExecutingLine(ByVal executingLine As Int32)
        If previouslyExecutingLine <> -1 Then
            'erase previous line
            PaintRTFLine(previouslyExecutingLine, MacroTextBox.BackColor, True)
        End If

        'highlight current line
        PaintRTFLine(executingLine, My.Settings.ColorHighlightExecutingCommand, True)
        previouslyExecutingLine = executingLine

        'unselect current line
        MacroTextBox.Select(MacroTextBox.GetFirstCharIndexOfCurrentLine, 0)

        'refresh form
        Me.Refresh()
        Application.DoEvents()
    End Sub

#End Region


    Private Sub EquationButton_Click(sender As Object, e As EventArgs) Handles EquationButton.Click
        Me.TrimRTFBlankLines()
        Me.HighlightText()
    End Sub



End Class
